package com.partsoft.dits.log;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import com.partsoft.dits.ConfigurableBean;
import com.partsoft.dits.dsm.DataSourceFactory;
import com.partsoft.dits.message.DataProperty;

public class ContextJdbcDataChangeLogStorage extends BaseJdbcDataChangeLogStorage implements ConfigurableBean,
		ApplicationListener<ApplicationEvent>, ApplicationContextAware {

	private DataSourceFactory dataSourceFactory;

	private String storageDataSourceName;

	protected ApplicationContext ownerContext;

	private boolean autoCreateTable = false;

	private boolean alreadyInited = false;

	public void setAutoCreateTable(boolean autoCreateTable) {
		this.autoCreateTable = autoCreateTable;
	}

	public boolean isAutoCreateTable() {
		return autoCreateTable;
	}

	public void setDataSourceFactory(DataSourceFactory dataSourceFactory) {
		this.dataSourceFactory = dataSourceFactory;
	}

	public DataSourceFactory getDataSourceFactory() {
		return dataSourceFactory;
	}

	public void setStorageDataSourceName(String storageDataSourceName) {
		this.storageDataSourceName = storageDataSourceName;
	}

	public String getStorageDataSourceName() {
		return storageDataSourceName;
	}

	public void setApplicationContext(ApplicationContext context) throws BeansException {
		this.ownerContext = context;
	}

	protected boolean isAlreadyInited() {
		return alreadyInited;
	}

	public void finiContext() {
		synchronized (this) {
			if (isAlreadyInited()) {
				alreadyInited = false;
			}
		}
	}

	public void initContext() {
		synchronized (this) {
			if (isAlreadyInited())
				finiContext();
			boolean dataSourceNamed = StringUtils.hasText(getStorageDataSourceName());
			if (dataSourceNamed || resolveJdbcDataSource() != null) {
				if (dataSourceNamed) {
					setDataSource(getDataSourceFactory().getDataSource(getStorageDataSourceName()));
				}
			} else {
				throw new IllegalArgumentException("找不到变更日志保存数据源");
			}

			if (isAutoCreateTable()) {
				try {
					getLastChangeLog(new DataProperty(ContextJdbcDataChangeLogStorage.class.getName()));
				} catch (BadSqlGrammarException e) {
					String ftname = getTableFullName();
					Log.warn(String.format("无法获取数据表(%s)数据尝试进行创建，获取数据错误消息：%s。", ftname, e.getMessage()), e);
					try {
						doCreateStorageTable();
						Log.info(String.format("成功创建数据表(%s)", ftname));
					} catch (Throwable ecx) {
						throw new IllegalArgumentException(String.format("创建数据表(%s)失败:%s", ftname, ecx.getMessage()), ecx);
					}
				}
			}

			alreadyInited = true;
		}
	}

	public void onApplicationEvent(ApplicationEvent event) {
		if (ObjectUtils.nullSafeEquals(event.getSource(), ownerContext)) {
			if (event instanceof ContextRefreshedEvent) {
				initContext();
			} else if (event instanceof ContextClosedEvent) {
				finiContext();
			}
		}
	}
}
